/*
 * 文件名：AlipayServiceImpl_2.java
 * 版权：
 * 描述：TODO
 * 修改人：zuo liubo
 * 修改时间：2013-6-21 下午4:03:02
 */
package com.scpii.api.service.alipay.impl;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.scpii.api.common.Constants;
import com.scpii.api.domain.app.AppConfigs;
import com.scpii.api.domain.ec.Order;
import com.scpii.api.domain.ec.OrderDetail;
import com.scpii.api.persistence.app.AppConfigsMapper;
import com.scpii.api.service.alipay.AlipayService;
import com.scpii.api.service.alipay.base.AlipayConstants;
import com.scpii.api.service.alipay.base.DirectTradeCreateRes;
import com.scpii.api.service.alipay.base.ErrorCode;
import com.scpii.api.service.alipay.base.ResponseResult;
import com.scpii.api.service.alipay.util.AlipayUtil;
import com.scpii.api.service.alipay.util.MD5Signature;
import com.scpii.api.service.alipay.util.ParameterUtil;
import com.scpii.api.service.alipay.util.StringUtil;
import com.scpii.api.service.alipay.util.XMapUtil;

/**
 * @description TODO
 * @author zuo liubo
 * @date 2013-6-21
 */
@Service("alipayService")
public class AlipayServiceImpl implements AlipayService {

	@Resource
	private AppConfigsMapper appConfigsMapper;
	

	@Override
	public String pay(Order order) {
		// 前置条件获取支付信息
		List<AppConfigs> _appConfigs = appConfigsMapper.selectByType(order.getAppId(), AppConfigs.Type.ALIPAY);
		Map<String, String> appConfigs = AlipayUtil.appConfigs2Map(_appConfigs);
		Map<String, String> reqParams = prepareTradeRequestParamsMap(order, appConfigs);
		// 签名类型
		String signAlgo = AlipayConstants.SEC_ID;
		String reqUrl = AlipayConstants.REQ_URL;

		// 获取商户MD5 key
		String key = appConfigs.get(AppConfigs.ALIPAY_KEYWORD.PRIVATE_KEY);
		String sign = sign(reqParams, signAlgo, key);
		reqParams.put("sign", sign);

		ResponseResult resResult = new ResponseResult();
		String businessResult = "";
		try {
			resResult = send(reqParams, reqUrl, signAlgo, appConfigs);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		if (resResult.isSuccess()) {
			businessResult = resResult.getBusinessResult();
		} else {
			return null;
		}

		DirectTradeCreateRes directTradeCreateRes = null;
		XMapUtil.register(DirectTradeCreateRes.class);
		try {
			directTradeCreateRes = (DirectTradeCreateRes) XMapUtil.load(new ByteArrayInputStream(businessResult
					.getBytes("UTF-8")));
		} catch (UnsupportedEncodingException e) {
		} catch (Exception e) {
		}
		// 开放平台返回的内容中取出request_token
		String requestToken = directTradeCreateRes.getRequestToken();
		Map<String, String> authParams = prepareAuthParamsMap(requestToken, appConfigs);
		// 对调用授权请求数据签名
		String authSign = sign(authParams, signAlgo, key);
		authParams.put("sign", authSign);
		String redirectURL = "";
		try {
			redirectURL = getRedirectUrl(authParams, reqUrl);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (StringUtil.isNotBlank(redirectURL)) {
			return redirectURL;
		}
		return null;
	}

	private Map<String, String> prepareTradeRequestParamsMap(Order order, Map<String, String> appConfigs) {
		Map<String, String> requestParams = new HashMap<String, String>();
		// 商品名称
		String subject = "";
		List<OrderDetail> orderDetails = order.getOrderDetails();
		for (OrderDetail od : orderDetails) {
			subject = subject + od.getProductName() + "|";
		}
		subject = subject.substring(0, subject.length() - 1);

		if (subject.length() > 256) {
			subject = subject.substring(0, 250);
		}
		// 商品总价
		String totalFee = order.getTotalPrice().toString();
		// 外部交易号 这里取当前时间，商户可根据自己的情况修改此参数，但保证唯一性
		String outTradeNo = order.getOrderSn();
		// 卖家帐号
		String sellerAccountName = appConfigs.get(AppConfigs.ALIPAY_KEYWORD.SELLER_ACCOUNT);
		// 接收支付宝发送的通知的url
		String notifyUrl = Constants.ALIPAY_NOTIFY_URL;
		// 未完成支付，用户点击链接返回商户url
		String merchantUrl = Constants.ALIPAY_CALL_BACK_URL ;
		// req_data的内容
		String reqData = "<direct_trade_create_req>" + "<subject>" + subject + "</subject><out_trade_no>" + outTradeNo
				+ "</out_trade_no><total_fee>" + totalFee + "</total_fee><seller_account_name>" + sellerAccountName
				+ "</seller_account_name><notify_url>" + notifyUrl + "</notify_url><call_back_url>" + merchantUrl
				+ "</call_back_url><pay_expire>"+Constants.ALIPAY_PAY_EXPIRE+"</pay_expire>";
		reqData = reqData + "</direct_trade_create_req>";
		requestParams.put("req_data", reqData);
		requestParams.put("req_id", System.currentTimeMillis() + order.getOrderSn() + "");
		requestParams.putAll(prepareCommonParams(appConfigs));
		return requestParams;
	}

	private Map<String, String> prepareCommonParams(Map<String, String> appConfigs) {
		Map<String, String> commonParams = new HashMap<String, String>();
		commonParams.put("service", AlipayConstants.OAUTH_API_NAME);
		commonParams.put("sec_id", AlipayConstants.SEC_ID);
		commonParams.put("partner", appConfigs.get(AppConfigs.ALIPAY_KEYWORD.PART_ID));
		commonParams.put("call_back_url", Constants.ALIPAY_CALL_BACK_URL );
		commonParams.put("format", AlipayConstants.DATA_FORMAT);
		commonParams.put("v", AlipayConstants.VERSION);
		return commonParams;
	}

	private String sign(Map<String, String> reqParams, String signAlgo, String key) {

		String signData = ParameterUtil.getSignData(reqParams);

		String sign = "";
		try {
			sign = MD5Signature.sign(signData, key);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		return sign;
	}

	private ResponseResult send(Map<String, String> reqParams, String reqUrl, String secId,
			Map<String, String> appConfigs) throws Exception {
		String response = "";
		String invokeUrl = reqUrl + "?";
		URL serverUrl = new URL(invokeUrl);
		HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();

		conn.setRequestMethod("POST");
		conn.setDoOutput(true);
		conn.connect();
		String params = ParameterUtil.mapToUrl(reqParams);
		conn.getOutputStream().write(params.getBytes());

		InputStream is = conn.getInputStream();

		BufferedReader in = new BufferedReader(new InputStreamReader(is));
		StringBuffer buffer = new StringBuffer();
		String line = "";
		while ((line = in.readLine()) != null) {
			buffer.append(line);
		}
		response = URLDecoder.decode(buffer.toString(), "utf-8");
		conn.disconnect();
		return praseResult(response, secId, appConfigs);
	}

	private ResponseResult praseResult(String response, String secId, Map<String, String> appConfigs) throws Exception {
		// 调用成功
		HashMap<String, String> resMap = new HashMap<String, String>();
		String v = ParameterUtil.getParameter(response, "v");
		String service = ParameterUtil.getParameter(response, "service");
		String partner = ParameterUtil.getParameter(response, "partner");
		String sign = ParameterUtil.getParameter(response, "sign");
		String reqId = ParameterUtil.getParameter(response, "req_id");
		resMap.put("v", v);
		resMap.put("service", service);
		resMap.put("partner", partner);
		resMap.put("sec_id", secId);
		resMap.put("req_id", reqId);
		String businessResult = "";
		ResponseResult result = new ResponseResult();
		System.out.println("Token Result:" + response);
		if (response.contains("<err>")) {

			result.setSuccess(false);
			businessResult = ParameterUtil.getParameter(response, "res_error");

			// 转换错误信息
			XMapUtil.register(ErrorCode.class);
			ErrorCode errorCode = (ErrorCode) XMapUtil.load(new ByteArrayInputStream(businessResult.getBytes("UTF-8")));
			result.setErrorMessage(errorCode);

			resMap.put("res_error", ParameterUtil.getParameter(response, "res_error"));
		} else {
			businessResult = ParameterUtil.getParameter(response, "res_data");
			result.setSuccess(true);
			result.setBusinessResult(businessResult);
			resMap.put("res_data", businessResult);
		}
		// 获取待签名数据
		String verifyData = ParameterUtil.getSignData(resMap);
		// 对待签名数据使用支付宝公钥验签名
		boolean verified = MD5Signature.verify(verifyData, sign, appConfigs.get(AppConfigs.ALIPAY_KEYWORD.PRIVATE_KEY));

		if (!verified) {
			throw new Exception("验证签名失败");
		}
		return result;
	}

	private Map<String, String> prepareAuthParamsMap(String requestToken, Map<String, String> appConfigs) {
		Map<String, String> requestParams = new HashMap<String, String>();
		String reqData = "<auth_and_execute_req><request_token>" + requestToken
				+ "</request_token></auth_and_execute_req>";
		requestParams.put("req_data", reqData);
		requestParams.putAll(prepareCommonParams(appConfigs));
		// 支付成功跳转链接
		requestParams.put("call_back_url", Constants.ALIPAY_CALL_BACK_URL);
		requestParams.put("service",AlipayConstants.PAY_URL);
		return requestParams;
	}

	private String getRedirectUrl(Map<String, String> reqParams, String reqUrl) throws Exception {
		String redirectUrl = reqUrl + "?";
		redirectUrl = redirectUrl + ParameterUtil.mapToUrl(reqParams);
		return redirectUrl;
	}

}
